use axum::{
    Json,
    http::StatusCode,
    response::{IntoResponse, Response},
};

use tracing::{error};
use crate::base::res::Res;
/**
 * 快捷创建宏
 */

macro_rules! biz_code {
    ($(
        $variant:ident($code:expr, $msg:expr)
    ),* $(,)?) => {
        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub enum BizCode {
            $($variant,)*
        }

        impl BizCode {
            pub fn code(&self) -> i32 {
                match self {
                    $(Self::$variant => $code,)*
                }
            }

            pub fn msg(&self) -> &'static str {
                match self {
                    $(Self::$variant => $msg,)*
                }
            }

            pub fn from_code(code: i32) -> Option<Self> {
                match code {
                    $($code => Some(Self::$variant),)*
                    _ => None,
                }
            }
        }

        // 自动生成常量
        $(
            pub const $variant: BizCode = BizCode::$variant;
        )*
    };
}
biz_code!{
    SUCCESS(0,"成功"),
    FAIL(-1,"网络异常，请稍后重试"),
    SYSTEM_ERROR(500,"系统繁忙，请稍后重试"),
}

#[derive(Debug)]
pub enum AppError {
    Anyhow(anyhow::Error),
    Biz(BizCode),
}

impl AppError {
    pub fn biz(code:BizCode)->Self {
        Self::Biz(code)
    }

    pub fn system(e:anyhow::Error)->Self {
        error!("系统异常[system_error]:{}", e );
        Self::Biz(SYSTEM_ERROR)
    }
}

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let (code,msg)  = match self {
            AppError::Anyhow(e) =>{
                error!("系统异常[system_error]:{}", e );
                (SYSTEM_ERROR.code(),SYSTEM_ERROR.msg())
            },
            AppError::Biz(code)=>{
                (code.code(),code.msg())
            }
        };
        let res = Res::new(code,msg.to_string(),Some(""));
        (StatusCode::OK,Json(res)).into_response()
    }
}

impl From<anyhow::Error> for AppError {
    fn from(e: anyhow::Error) -> Self {
        AppError::system(e)
    }
}

impl From<BizCode> for AppError {
    fn from(code: BizCode) -> Self {
        AppError::Biz(code)
    }
}

pub fn sys_error(e: anyhow::Error)->BizCode {
    error!("系统异常[sys_error]:{}", e);
    SYSTEM_ERROR
}